/*
* This file is the main code of Texdi
* Copyright (C) <2017>  <alkeon> [alkeon@autistici.org]
   
* Texdi is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Texdi is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Texdi.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include "tedi2ad.h"
#include "exception.h"
using namespace std;
/*
 * This function converts a string with Tedi format and return 
 * a string with HTML format.
 * Header and footer are void by default.
 */
string tedi2ad(string text, string header, string footer){
	stringstream index(text);
	string line;
	string return_text;
	int control=0;
	int open_brackets=0;
	while(getline(index,line)){
		if(line[0]!='<'){
			size_t key1=line.find('{');
			size_t bra1=line.find("[(");
			size_t hash=line.find('#');
			if(hash!=std::string::npos){
				line=titles_ad(line);
				return_text+=line+"\n";
			}else{
				size_t li=line.find("--");
				if(li!=string::npos){
					line=line.erase(li,2);

					line=line.insert(li,"- ");
				}
				size_t ul=line.find("__");
				size_t ulf=line.find(",,");
				if(ul!=string::npos or ulf!=string::npos)
					return_text+="\n";
				size_t comi=line.find("\"");
				if(comi!=std::string::npos){
					if(line[line.size()-1]=='"')
						line=line.substr(1,line.size()-2);
					else
						throw Invalid("Missing end quotes.",line);
				}else{
					int etiq=main_tag_ad(line);
					size_t key=line.find("{(");
					if(key==string::npos && key1!=string::npos)
						throw Invalid("Missing block tag.",line);
					size_t bra=line.find("[(");
					if(bra==string::npos && bra1!=string::npos)
						throw Invalid("Missing link tag.",line);
					while(etiq!=-1){
						if(etiq==2){
							size_t lla2=line.find("}");
							if(lla2==std::string::npos){
								++open_brackets;
								line=incomplete_blocks_ad(line);
							}else
								line=blocks_ad(line);
							
						}else{
							if(etiq==0){
								size_t par1=line.find("(");
								if(par1!=std::string::npos )
									line=images_ad(line);
									
							}else{
								line=links_ad(line);
							}
						}
						etiq=main_tag_ad(line);
					}
					size_t lla2=line.find("}");
					if(lla2!=string::npos){
						if(open_brackets==0)
							throw Invalid("Missing '{' in block tag.",line);
						--open_brackets;
						line=line.erase(lla2,1);
					}
				}
					
				// Table conversion
				size_t hor=line.find("|");
				if(control==0){
					size_t hor1=line.rfind("|");
					if(hor!=string::npos && hor!=hor1){
						return_text+="|=======\n";
						table_ad(line);
						control=1;
					}
				}else{
					if(hor==string::npos){
						return_text+="|=======\n";
						control=0;
					}else{
						table_ad(line);
					}
				}
				//Table conversion
				size_t minor=line.rfind(" ");
				if(minor==line.size()-1 && line.size()>1){
					return_text+=line+ "\n\n";
				}else{
					if(ulf==string::npos && ul==string::npos && hash==string::npos && hor==string::npos){
						return_text+=line+ "\n";
					}
				}
			}		
		}else{
			if(line[1]!='!'){
				if(line[1]=='>'){
					line=line.erase(0,2);
					return_text+=line+ "\n\n";
				}else{
					line=line.erase(0,1);
					line=line.insert(0,"`");
					return_text+=line+ "`\n\n";
				}
			}
		}
	}
	if(open_brackets>0)
		throw Invalid("Missing '}' in document.","End of file");
	return return_text;
}
/*
 * Detects next tag
 * Returns 
 * 0: images
 * 1: links
 * 2: blocks
 * -1: No tag
 */
int main_tag_ad(string line){
	int etiq=-1;
	size_t cont=line.size();
	size_t lla=line.find("{(");
	size_t paren=line.find("([");
	size_t corch=line.find("[(");
	if(lla!= string::npos && lla<cont){
		etiq=2;
		cont=lla;
	}
	if(corch != string::npos && corch<cont){
		cont=corch;
		etiq=1;
	}
	if(paren != string::npos && paren<cont){
		etiq=0;
	}
	return etiq;
}
/*
 * Deletes parentheses and adds ascii text of a image.
 *
 */
string images_ad(string line){
	size_t start_tag=line.find("([");
	string aux="image::";
	if(start_tag!= string::npos){
		line=line.erase(start_tag,2);
		line=line.insert(start_tag, aux);
		size_t par1=line.find("]");
		if(par1!=string::npos){
			line=line.erase(par1,1);
			aux="[";
			line=line.insert(par1,aux);
			size_t brack=line.rfind(")");
			if(brack==string::npos)
				throw Invalid("Missing ']' in link tag.",line);
			else
			  	line[brack]=']';
		}else
			throw Invalid("Missing ')' in link tag.",line);
	}else
		throw Invalid("Missing link tag.",line);

	return line;
}
/*
 * Convert Tedi link to a HTML link
 *
 */
string links_ad(string line){
	size_t start_tag=line.find("[(");
	string aux;
	if(start_tag!= string::npos){
		line=line.erase(start_tag,2);
		size_t par1=line.find(")");
		if(par1!=string::npos){
			line=line.erase(par1,1);
			aux="[";
			line=line.insert(par1,aux);
			size_t brack=line.rfind("]");
			if(brack==string::npos)
				throw Invalid("Missing ']' in link tag.",line);
		}else
			throw Invalid("Missing ')' in link tag.",line);
	}else
		throw Invalid("Missing link tag.",line);

	return line;
}
/*
 * Deletes hashes and adds HTML text of a title.
 *
 */
string titles_ad(string line){
	size_t exa1=line.find("#");
	int ti=0;
	while(exa1!=std::string::npos && line[exa1]=='#'){
		++exa1;
		line=line.substr(exa1,line.size()-1);
		exa1=line.find("#");
		++ti;
	}
	string aux=line;
	line+="\n";
	char let;
	if(ti==1)
		let='-';
	else if(ti==2)
		let='~';
	else if(ti==3)
		let='^';
	else
		let='+';
	for(unsigned i=0;i<aux.length();++i){
		line+=let;
	}
	line+="\n";
	return line;
}
/*
 * Deletes brackes and parentheses. Adds HTML text 
 * of a <div> container.
 *
 */
string blocks_ad(string line){
	size_t key1=line.find("{(");

	if(key1!= std::string::npos){
		size_t par2=line.find(")");
		if(par2!=string::npos){
			int delete_class =par2-key1;
			line=line.erase(key1,delete_class+1);
			size_t key2=line.rfind("}");
			if(key2!=string::npos){
				line=line.erase(key2,1);
			}else
				throw Invalid("Missing '}' in block tag.",line);
		}else
			throw Invalid("Missing ')' in block tag.",line);
	}else
		throw Invalid("Missing block tag.",line);
	return line;
}
/*
 * Deletes brackes and parentheses. Adds HTML text 
 * of a <div> container.
 *
 */
string incomplete_blocks_ad(std::string line){
	size_t key1=line.find("{(");
	if(key1!= std::string::npos){
		size_t par2=line.find(")");
		if(par2!=string::npos){
			int delete_class =par2-key1;
			line=line.erase(key1,delete_class+1);
			size_t key2=line.find("}");
			if(key2!=string::npos)
				throw Invalid("Unexpected '}' in incomplete block tag.",line);
		}else
			throw Invalid("Missing ')' in block tag.",line);
	}else
		throw Invalid("Missing block tag.",line);
	return line;
}

/*
 * Convert Tedi table (line by line)
 *
 */
void table_ad(string& line){
	size_t hor=line.find("|");
	if(hor!=string::npos){
		hor=line.find("|");
		if(hor!=string::npos){
			size_t tam=line.size()-1;
			line.erase(tam);
		}else{
			throw Invalid("Expected '|' in table", line);
		}
	}else{
		throw Invalid("Expected '|' in table", line);
	}
}
